/**
 * @author Austin Andrews (Templarian)
 * @authorurl http://templarian.com
 * @framework DD Framework
 * @licence New BSD License
 * @licenceurl http://ddframework.googlecode.com/svn/trunk/license.txt
 * @overview Core Legacy Support
 */
/**
 * Use as a function or to access properties
 * @namespace dd
 * @property
 *  Access modules and core functionality
 * @function
 *  Select a dom element by id attribute
 *  @param id {string} An id attribute of a visible dom element
 *  @returns dd.fn
 * @function
 *  Select a dom element by passing an object
 *  @param dom {object} Dom elment
 *  @returns dd.fn
*/
var dd = function(o1, o2)
{
    return dd.is(o2)
        ? function()
        {
            dd.combine(this, o2);
            o1.apply(this, arguments);
        }
        : dd.is(o1, "string")
            ? dd.fn.init.call(dd, o1)
            : (dd.is(["projects", "modules"], o1))
                ? dd._c.call(dd, o1)
                : dd.fn.init.call(dd, o1);
};
/**
 * is
 * @namespace dd.is
 * @function
 *  Check if variable is Undefined
 *  @param value {} Value to check
 *  @param type {string} Type to check against
 *  @returns element
 * @function
 *  Check if key is in object
 *  @param key {} Key
 *  @param object {string} Object
 *  @returns element
 */
dd.is = function(v, t)
{
    var _v = v instanceof Array ? "array" : typeof(v);
    var _t = t instanceof Array ? "array" : typeof(t);
    if(_t === "undefined")
    {
        return v === null ? false : _v !== "undefined";
    }
    else if(_t === "string")
    {
        return _v === t;
    }
    else if(_t === "array")
    {
        if(this._a !== t)
        {
            this._o = {};
            for(var i = 0; i < t.length; i++)
            {
                this._o[t[i]] = null;
            }
            this._a = t;
        }
        return v in this._o;
    }
    else if(_v === "array")
    {
        for(var i = 0; i < v.length; i++)
        {
            if(v[i] in t)
            {
                return true;
            }
        }
        return false;
    }
    else if(_t == "object")
    {
        return typeof(t[v]) !== "undefined";
    }
    alert("Error: dd.is");
};
/**
 * Overloaded function to extend the framework
 * @namespace dd.extend
 * @function
 *  Extend the core of the framework
 *  @param obj {object} Ex:
 *  "Example"[javascript]@@
 *  {
 *      // Called on load
 *      init:function()
 *      {
 *          [...]
 *      },
 *      //module.submodule()
 *      func:function()
 *      {
 *          [...]
 *      }
 *  }
 *  @@
 * @function
 *  Define new modules included with the framework
 *  @param moduleName {string} Ex: "module.submodule"
 *  @param obj {object} Ex:
 *  "Example"[javascript]@@
 *  {
 *      // Called on load
 *      init:function()
 *      {
 *          [...]
 *      },
 *      //module.submodule()
 *      func:function()
 *      {
 *          [...]
 *      }
 *  }
 *  @@
*/
dd.extend = function(o1, o2)
{
    if(dd.is(o1, "string") && (!dd.is(o2) || dd.is(o2, "function")))
    {
        var nns = dd.clone(this.ns);
        nns.push(o1);
        this[o1] = dd.extend({}, {
            func:dd.extend,
            isSetup:false,
            parent:this,
            ns:nns,
            extend:dd.extend
        });
        dd._loadFile(dd._files.push({
            ns:nns,
            folder:(nns[0] == "dd" ? dd.pathCore + "dd" : dd.path + nns[1]) + "/",
            cb:typeof(o2) == "function" ? o2 : function(){}
        }) - 1);
        return true;
    }
    else if(dd.is(o1, "object") && dd.is(o2, "object"))
    {
        var r = {}; // Temp object
        if(typeof(o2.func) != "undefined")
        {
            r = (function(func, ns)
            {
                return function()
                {
                    var s = dd._nsToObj(dd, ns);
                    if(typeof(s._i) == "undefined")
                    {
                        s._i = true;
                        return func.apply(s, arguments);
                    }
                    else
                    {
                        return s.func.apply(this, arguments);
                    }
                };
            })(o2.func, typeof(o2.ns) == "undefined" ? o1.ns : o2.ns);
        }
        for(var i in o1)
        {
            r[i] = o1[i];
        }
        for(var i in o2)
        {
            if(i != "fn") // don't add these
            {
                o1[i] = r[i] = o2[i];
            }
        }
        if(typeof(o2.fn) != "undefined")
        {
            dd._extend(dd.fn, o2.fn);
        }
        return r;
    }
    else if(typeof(o1) == "object" && typeof(o2) == "undefined")
    {
        if(typeof(this.ns) == "undefined")
        {
            dd._extend(this, o1);
        }
        else
        {
            dd.extend(this, o1);
        }
        return this;
    }
    else
    {
        alert("Error: Overload for dd.extend does not exist");
        return false;
    }
};
dd._extend = function(a, b)
{
    for(var i in b)
    {
        var g = {}, s = {};
        if(typeof(b.__lookupGetter__) != "undefined")
        {
            g = b.__lookupGetter__(i);
            s = b.__lookupSetter__(i);
        }
        else
        {
            g = false;
            s = false;
        }
        if(g || s)
        {
            if(g)
            {
                a.__defineGetter__(i, g);
            }
            if(s)
            {
                a.__defineSetter__(i, s);
            }
        }
        else
        {
            a[i] = b[i];
        }
    }
    return a;
};
dd.extend({
    ns:["dd"],
    _c:function(o)
    {
        if("config" in o)
        {
            
            var h = document.getElementsByTagName("head")[0].children;
            for(var i in h)
            {
                var n = dd.isObject(h[i]) ? h[i].nodeName.toLowerCase() : "";
                if(n == "script")
                {
                    if(/dd\.js$/.test(h[i].getAttribute('src')))
                    {
                        this.path = this.pathCore = /(.*)dd\/dd\.js$/.exec(h[i].getAttribute('src'))[1];
                    }
                }
            }
            if(dd.is("path", o.config))
            {
                this.path = o.config.path;
            }
            if(dd.is("modules", o.config))
            {
                for(var i in o.config.modules)
                {
                    var a = o.config.modules[i].split(/\./);
                    var n = a.pop();
                    dd._nsToObj(dd, a).extend(n);
                }
                dd._moduleCount = o.config.modules.length;
            }
            if(dd.is("projects", o.config))
            {
                for(var i in o.config.projects)
                {
                    if(!dd.is(i, this.project))
                    {
                        this.project.extend(i);
                    }
                    for(var j in o.config.projects[i])
                    {
                        var a = o.config.projects[i][j].split(/\./);
                        a.splice(0, 0, i);
                        var n = a.pop();
                        dd._nsToObj(dd.project, a).extend(n);
                    }
                }
            }
        }
        if("onReady" in o)
        {
            dd._onReady = o.onReady;
        }
        if("onLoad" in o)
        {
            dd._onLoad = o.onLoad;
        }
    },
    _onReady:function(){},
    _onLoading:function(){},
    isE:function(o)
    {
        if(dd.isString(o))
        {
            return false;
        }
        var a = ["config", "onReady", "onLoad", "onLoading", "onComplete"];
        for(var i in a)
        {
            if(a[i] in o)
            {
                return true;
                break;
            }
        }
        return false;
    },
    toL:function(s)
    {
        return dd.is(s) ? s.toLowerCase() : "";
    },
    toU:function(s)
    {
        return dd.is(s) ? s.toUpperCase() : "";
    },
    clone:function(a)
    {
        var b = [];
        for(var i in a)
        {
            b[i] = a[i];
        }
        return b;
    },
    /**
     * Trim whitespace
     * @namespace dd.trim
     * @function
     *  @param str {string} String to trim
     */
    trim:function(v)
    {
        return v.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
    },
    /**
     * Function definition for dd
     * @namespace dd.fn
     * @property
     *  Stores all function calls for dd
    */
    fn:{
        /**
         * Initiates 
         * @namespace dd.fn.init
         * @function
         *  Select a dom element by id attribute
         *  @param id {string} An id attribute of a visible dom element
         *  @returns dd.fn
         * @function
         *  Select a dom element by passing an object
         *  @param dom {object} Dom elment
         *  @returns dd.fn
         */
        init:function(o)
        {
            this.fn.e = typeof(o) == "object" ? "self" in o ? o.self : o :
            document.getElementById(o) ? document.getElementById(o) : null;
            this.fn.data = typeof(o) == "object" ? "data" in o ? o : {} : {};
            if(this.fn.e)
            {
                this.fn.nodeName = "nodeName" in this.fn.e ? dd.toL(this.fn.e.nodeName) : null;
                this.fn.value = this.fn.nodeName ? this.fn.nodeName == "input"
                    || this.fn.nodeName == "textarea"
                    || this.fn.nodeName == "select" ? (function(e)
                    {
                        return function(v)
                        {
                            if(e.type == "checkbox")
                            {
                                return dd.is(v) ? e.checked = v : e.checked;
                            }
                            else
                            {
                                return dd.is(v) ? e.value = v : e.value;
                            }
                        }
                    })(this.fn.e) : null : null;
                this.fn.text = this.fn.nodeName ? (function(e){return function(v)
                {
                    if(dd.is(v))
                    {
                        while(e.childNodes.length)
                        {
                            e.removeChild(e.childNodes[0]);
                        }
                        e.appendChild(document.createTextNode(v));
                        return v;
                    }
                    else
                    {
                        return e.childNodes.length > 0 ? e.childNodes[0].nodeValue : "";
                    }
                };
                })(this.fn.e) : null;
                this.fn.canvas = this.fn.nodeName ? this.fn.nodeName == "canvas"
                                    ? this.fn.e.getContext('2d') : null : null;
            }
            else
            {
                alert("Error: Element does not exist");
            }
            this.fn.scope = this;
            return this.fn;
        },
        /**
         * Initiates 
         * @namespace dd.fn.addElement
         * @function
         *  Add element to DOM
         *  @param name {string} Element name
         *  @returns element
         * @function
         *  Add element to DOM
         *  @param name {string} Element name
         *  @param innerText {string} Inner text
         *  @returns element
         *  @function
         *  Add element to DOM
         *  @param name {string} Element name
         *  @param innerText {object} Attributes
         *  @returns element
         * @function
         *  Add element to DOM
         *  @param name {string} Element name
         *  @param innerText {string} Inner text
         *  @param attributes {object} Attributes
         *  @returns element
         * @function
         *  Add element to DOM
         *  @param namespace_name {object} Dom elment, ex: {"svg":"rect"}
         *  @returns dd.fn
         * @function
         *  Add element to DOM
         *  @param namespace_name {object} Dom elment, ex: {"svg":"rect"}
         *  @param attribute {object} Attributes
         *  @returns dd.fn
         * @function
         *  Add element to DOM
         *  @param namespace_name {object} Element name, ex: {"svg":"rect"}
         *  @param innerText {string} Inner text
         *  @param id {object} Attributes
         *  @returns dd.fn
         */
        addElement:function(o1, o2, o3, o4)
        {
            var e = {};
            if(typeof(o1) == "string")
            {
                e = document.createElement(o1);
            }
            else if(typeof(o1) == "object")
            {
                for(var i in o1)
                {
                    e = document.createElementNS(dd._ns[i], i + ":" + o1[i]);
                }
            }
            if(typeof(o2) == "object")
            {
                for(var j in o2)
                {
                    e.setAttribute(j, o2[j]);
                }
            }
            else if(typeof(o2) == "string" || typeof(o2) == "number")
            {
                if(o2 != "")
                {
                    e.appendChild(document.createTextNode(o2));
                }
            }
            if(o3)
            {
                for(var k in o3)
                {
                    e.setAttribute(k, o3[k]);
                }
            }
            if(dd.isBool(o1) || dd.isBool(o2) || dd.isBool(o3) || dd.isBool(o4))
            {
                this.e.insertBefore(e, this.e.firstChild);
            }
            else
            {
                this.e.appendChild(e);
            }
            return {self:e};
        },
        /**
         * Initiates 
         * @namespace dd.fn.removeElement
         * @function
         *  Removes element from DOM
         */
        removeElement:function()
        {
            this.e.parentNode.removeChild(this.e);
        },
        /**
         * Initiates 
         * @namespace dd.fn.clearElements
         * @function
         *  Add element to DOM
         *  @param name {string} Element name
         *  @returns element
         */
        clearElements:function()
        {
            var base = this.e;
            while(base.childNodes[0])
            {
                base.removeChild(base.childNodes[0]);
            }
        },
        /**
         * Initiates 
         * @namespace dd.fn.addClass
         * @function
         *  Add element to DOM
         *  @param name {string} Element name
         *  @returns element
         */
        addClass:function(name)
        {
            var c = this.e.className.split(/ /);
            c.push(name);
            this.e.className = dd.trim(c.join(" "));
            return this;
        },
        /**
         * Initiates 
         * @namespace dd.fn.removeClass
         * @function
         *  Add element to DOM
         *  @param name {string} Element name
         *  @returns element
         */
        removeClass:function(name)
        {
            this.e.className = dd.trim((this.e.className + " ").replace(name + " ", ""));
            return this;
        },
        /**
         * Initiates 
         * @namespace dd.fn.clearClass
         * @function
         *  Add element to DOM
         *  @param name {string} Element name
         *  @returns element
         */
        clearClass:function()
        {
            this.e.className = "";
            return this;
        },
        /**
         * Checks if class exists
         * @namespace dd.fn.classExists
         * @function
         *  Add element to DOM
         *  @param name {string} Class name
         *  @returns boolean
         */
        hasClass:function(name)
        {
            return !!~(" " + this.e.className + " ").indexOf(" " + name + " ");
        },
        /**
         * Initiates 
         * @namespace dd.fn.setAttribute
         * @function
         *  Add element to DOM
         *  @param name {string} Element name
         *  @returns element
         */
        setAttribute:function(name, value)
        {
            this.e.setAttribute(name, value);
        },
        /**
         * Initiates 
         * @namespace dd.fn.getAttribute
         * @function
         *  Add element to DOM
         *  @param name {string} Element name
         *  @returns element
         */
        getAttribute:function(name)
        {
            return this.e.getAttribute(name);
        },
        /**
         * Initiates 
         * @namespace dd.fn.removeAttribute
         * @function
         *  Add element to DOM
         *  @param name {string} Element name
         *  @returns element
         */
        removeAttribute:function(name)
        {
            this.e.removeAttribute(name);
        },
        focus:function()
        {
            this.e.focus();
        },
        select:function()
        {
            this.e.select();
        },
        trigger:function(e, v)
        {
            v = dd.is(v) ? v : {};
            for(var i = 0; i < this.data.event[e].length; i++)
            {
                this.data.event[e][i].call(v);
            }
        },
        bind:function(e, f)
        {
            if(!("data" in this))
            {
                this.data = {};
            }
            if(!("event" in this.data))
            {
                this.data.event = {};
            }
            if(!(e in this.data.event))
            {
                this.data.event[e] = [];
            }
            if(dd.is(f))
            {
                this.data.event[e].push(f);
            }
        },
        /**
         * Sets or gets properties for objects
         */
        property:function(p, v)
        {
            var t = this.data[p];
            if(typeof(t) == "function")
            {
                return dd.is(v) ? this.data[p].call({set:true,get:false,value:v})
                                : this.data[p].call({set:false,get:true});
            }
            else
            {
                return dd.is(v) ? this.data[p] = v
                                : this.data[p];
            }
        }
    },
    _o:{},
    _a:{},
    /**
     * is
     * @namespace dd.is
     * @function
     *  Check if variable is Undefined
     *  @param value {} Value to check
     *  @param type {string} Type to check against
     *  @returns element
     * @function
     *  Check if key is in object
     *  @param key {} Key
     *  @param object {string} Object
     *  @returns element
     */
    is:function(v, type)
    {
        if(typeof(type) == "string")
        {
            return typeof(v) === type;
        }
        else if(type instanceof Array)
        {
            if(this._a != type)
            {
                this._o = {};
                for(var i = 0; i < type.length; i++)
                {
                    this._o[type[i]] = null;
                }
                this._a = type;
            }
            return v in this._o;
        }
        else if(typeof(type) == "object")
        {
            return typeof(type[v]) !== "undefined";
        }
        else
        {
            return v === null ? false : typeof(v) !== "undefined";
        }
    },
    /**
     * isFunction
     * @namespace dd.isFunction
     * @function
     *  Check if variable is a function
     *  @param v {var} Variable to check
     *  @returns boolean
     */
    isFunction:function(v)
    {
        return this.is(v, "function");
    },
    /**
     * isString
     * @namespace dd.isString
     * @function
     *  Check if variable is a string
     *  @param v {var} Variable to check
     *  @returns boolean
     */
    isString:function(v)
    {
        return this.is(v, "string");
    },
    /**
     * isArray
     * @namespace dd.isArray
     * @function
     *  Check if variable is an array
     *  @param v {var} Variable to check
     *  @returns boolean
     */
    isArray:function(v)
    {
        return (v instanceof Array);
    },
    /**
     * isBool
     * @namespace dd.isBool
     * @function
     *  Check if variable is a boolean
     *  @param v {var} Variable to check
     *  @returns boolean
     */
    isBool:function(v)
    {
        return this.is(v, "boolean");
    },
    /**
     * isNumber
     * @namespace dd.isNumber
     * @function
     *  Check if variable is a number
     *  @param v {var} Variable to check
     *  @returns boolean
     */
    isNumber:function(v)
    {
        return this.is(v, "number");
    },
    /**
     * isInteger
     * @namespace dd.isObject
     * @function
     *  Check if variable is an integer
     *  @param v {var} Variable to check
     *  @returns boolean
     */
    isInteger:function(v)
    {
        return parseInt(v, 10) === v;
    },
    /**
     * isObject
     * @namespace dd.isObject
     * @function
     *  Check if variable is an object
     *  @param v {var} Variable to check
     *  @returns boolean
     */
    isObject:function(v)
    {
        return this.is(v, "object");
    },
    /**
     * isNull
     * @namespace dd.isNull
     * @function
     *  Check if variable is null
     *  @param v {var} Variable to check
     *  @returns boolean
     */
    isNull:function(v)
    {
        return (v === null);
    },
    /**
     * Attaches JavaScript File
     * @namespace dd.fn.clearElements
     * @function
     *  Attaches JavaScript File 
     *  @param file {string} File
     *  @returns element
     */
    addJS:function(file, cb)
    {
        var headID = document.getElementsByTagName("head")[0];         
        var newScript = document.createElement('script');
        newScript.type = 'text/javascript';
        newScript.src = file;
        if(dd.is(cb))
        {
            newScript = dd(cb, {file:file});
        }
        headID.appendChild(newScript);
        return this;
    },
    /**
     * Removes JavaScript file
     * @namespace dd.fn.clearElements
     * @function
     *  Removes JavaScript file
     *  @param file {string} Element name
     *  @returns dd
     */
    removeJS:function(file)
    {
        var headID = document.getElementsByTagName("head")[0].children;
        for(var i in headID)
        {
            if(headID[i].nodeName.toLowerCase() == "script")
            {
                if(headID[i].getAttribute('src') == file)
                {
                    headID[i].parentNode.removeChild(headID[i]);
                }
            }
        }
        return this;
    },
    /**
     * Attach CSS stylesheet 
     * @namespace dd.fn.clearElements
     * @function
     *  Remove CSS stylesheet
     *  @param file {string} File
     *  @returns dd
     */
    addCSS:function(file)
    {
        var headID = document.getElementsByTagName("head")[0];         
        var cssNode = document.createElement('link');
        cssNode.type = 'text/css';
        cssNode.rel = 'stylesheet';
        cssNode.href = file;
        cssNode.media = 'screen';
        headID.appendChild(cssNode);
        return this;
    },
    /**
     * Remove CSS stylesheet 
     * @namespace dd.fn.removeCSS
     * @function
     *  Remove CSS stylesheet
     *  @param file {string} File
     *  @returns dd
     */
    removeCSS:function(file)
    {
        var headID = document.getElementsByTagName("head")[0].children;
        for(var i in headID)
        {
            if(typeof(headID[i]) != "undefined")
            {
                if(headID[i].nodeName.toLowerCase() == "link")
                {
                    if(headID[i].getAttribute('href') == file)
                    {
                        headID[i].parentNode.removeChild(headID[i]);
                    }
                }
            }
        }
        return this;
    },
    /**
     * Initiates 
     * @namespace dd.project
     * @property
     *  Access projects
     */
    project:{
        parent:this,
        ns:["project"],
        extend:function(n, cb)
        {
            var nns = dd.clone(this.ns);
            nns.push(n);
            this[n] = dd.extend({}, {
                func:dd.extend,
                isSetup:false,
                ns:nns,
                extend:dd.extend
            });
            dd._loadFile(dd._files.push({
                ns:nns,
                folder:dd.path + n + "/",
                cb:typeof(cb) == "function" ? cb : function(){}
            }) - 1);
        }
    },
    _files:[],
    _modules:[],
    path:"scripts/",
    pathCore:"scripts/",
    _moduleCount:0,
    _loadFilesCount:0,
    _loadFile:function(i)
    {
        var ns = this._files[i].ns,
            f = this._files[i].folder,
            n = ns.join(".");
        if(ns[0] == "dd")
        {
            dd.addJS(f + n + ".js");
        }
        else
        {
            dd.addJS(f + n.replace("project.", "") + ".js");
        }
        clearInterval(dd._loadInterval);
        dd._loadFiles();
    },
    ready:false,
    _nsToObj:function(s, a)
    {
        if(a.length > 0)
        {
            for(var i = (a[0] == "dd" ? 1 : 0); i < a.length; i++)
            {
                s = s[a[i]];
            }
        }
        return s;
    },
    _loadFiles:function()
    {
        for(var i = dd._loadFilesCount; i < dd._files.length; i++)
        {
            var ns = dd._files[i].ns,
                f = dd._files[i].folder,
                n = ns.join();
            var file = dd._nsToObj(dd, ns);
            if(ns[0] == "dd")
            {
                if(typeof(file.init) == "undefined")
                {
                    dd._loadInterval = setTimeout(dd._loadFiles, 200);
                    break;
                }
                dd._files[i].cb.call(file);
                file.init.call(file);
                dd._onLoading.call({isModule:true, dom:dd.ready, ns:ns});
                dd._loadFilesCount++;
                if(dd._loadFilesCount == dd._moduleCount - 1)
                {
                    if("_onLoad" in dd)
                    {
                        dd._onLoad.call({isModule:false, dom:dd.ready, ns:ns});
                    }
                }
            }
            else
            {
                if(typeof(file.init) == "undefined" || typeof(dd.html) == "undefined")
                {
                    dd._loadInterval = setTimeout(dd._loadFiles, 200);
                    break;
                }
                file.isSetup = true;
                dd._loadFilesCount++;
                dd._files[i].cb.call(file);
                file.init.call(file);
                if("_onLoad" in dd)
                {
                    dd._onLoad();
                    delete(dd._onLoad);
                }
            }
        }
    },
    _load:function()
    {
        dd.html = document.getElementsByTagName("html")[0];
        dd.html.head = document.getElementsByTagName("head")[0];
        dd.html.body = document.getElementsByTagName("body")[0];
        dd._onReady();
    },
    _ns:{
        "svg":"http://www.w3.org/2000/svg"
    }
});
/* Initialise */
if("addEventListener" in window)
{
    window.addEventListener("load", dd._load, false);
}
else
{
    window.attachEvent("onload", dd._load);
}